package com.ynet.middleground.contract.model;

import java.io.File;
import java.io.FileInputStream;
import java.time.LocalDateTime;
import java.util.*;

import org.apache.commons.lang.StringUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ynet.core.common.PagerInfo;
import com.ynet.core.exception.BusinessException;
import com.ynet.file.service.FileService;
import com.ynet.middleground.contract.bean.*;
import com.ynet.middleground.contract.constant.OperationTypeEnum;
import com.ynet.middleground.contract.constant.SystemConsts;
import com.ynet.middleground.contract.dao.ArchiveMapper;
import com.ynet.middleground.contract.dao.ArchiveOperationLogMapper;
import com.ynet.middleground.contract.dao.ContractMapper;
import com.ynet.middleground.contract.dto.ArchiveDto;
import com.ynet.middleground.contract.entity.Archive;
import com.ynet.middleground.contract.entity.ArchiveOperationLog;
import com.ynet.middleground.contract.entity.Contract;
import com.ynet.middleground.contract.entity.Template;
import com.ynet.middleground.contract.utils.CommUtils;
import com.ynet.middleground.contract.utils.GeneralService;
import com.ynet.middleground.user.bean.QueryUserInfoReq;
import com.ynet.middleground.user.dto.UserInfoDto;

/**
 * 档案管理事务业务处理
 *
 * @author daigaole
 */
@Component
public class ArchiveManagementModel extends ServiceImpl<ArchiveMapper, Archive> {

    /**
     * 操作成功
     */
    public static final String SUCCESSFUL = "操作成功";

    /**
     * 根据对象的属性复制到另一对象上的同名属性值
     */
    @Autowired
    Mapper dozerBeanMapper;

    /**
     * 合约主表dao
     */
    @Autowired
    ContractMapper contractMapper;

    /**
     * 通用公共方法
     */
    @Autowired
    GeneralService generalService;

    /**
     * 档案统计表dao
     */
    @Autowired
    ArchiveOperationLogMapper archiveOperationLogMapper;

    /**
     * 用户中心服务调用模块
     */
    @Autowired
    UserCenterModel userCenterModel;

    @Autowired
    private TemplateModel templateModel;

    @Autowired
    private TemplateOperationLogModel templateOperationLogModel;

    @Autowired
    private FileService fileService;

    @Autowired
    private CommUtils commUtils;

    /**
     * 新建档案
     *
     * @param requestObj 新建档案请求对象
     * @return 档案id
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer newArchive(NewArchiveReq requestObj) {

        Integer operationUserId = requestObj.getOperationUserId();
        Archive archive = dozerBeanMapper.map(requestObj, Archive.class);

        // 若上送业态 id，则查询业态是否有效
        if (null != requestObj.getFormatId()) {
            userCenterModel.getFormatOrgInfo(requestObj.getFormatId(), requestObj);
        }

        // 校验操作员id是否有效
        QueryUserInfoReq queryUserInfoReq =
            generalService.getQueryUserInfoReq(requestObj, requestObj.getOperationUserId());
        if (!generalService.isUserIdCorrect(queryUserInfoReq)) {
            throw new BusinessException("用户id不存在", "ECCT0102");
        }
        archiveUpdateOperationIdAndDate(archive, operationUserId, false);
        archive.setGmtSubmission(archive.getGmtCreate());
        // add by liwq on 2021-09-30
        // 添加档案涉及人名称，涉及企业名称
        if (requestObj.getArchiveNaturalPersonId() != null && requestObj.getArchiveEnterpriseId() != null) {
            throw new BusinessException("档案涉及自然人ID和档案涉及企业ID不能同时上送", "ECCT0103");
        }
        UserInfoDto userInfo = null;
        if (requestObj.getArchiveNaturalPersonId() != null) {
            userInfo = userCenterModel.getUserInfo(requestObj.getArchiveNaturalPersonId(), requestObj.getChannel(),
                requestObj.getOperationUserId(), requestObj.getEnterpriseId());
            if (userInfo != null) {
                archive.setArchiveNaturalPersonName(userInfo.getUserBaseInformationDto().getUserName());
            }
        }
        if (requestObj.getArchiveEnterpriseId() != null) {
            userInfo = userCenterModel.getUserInfo(requestObj.getArchiveEnterpriseId(), requestObj.getChannel(),
                requestObj.getOperationUserId(), requestObj.getEnterpriseId());
            if (userInfo != null) {
                archive.setArchiveEnterpriseName(userInfo.getUserBaseInformationDto().getUserName());
            }
        }
        // add by liwq on 2021-09-30
        this.save(archive);
        insertArchiveOperationLog(archive.getId(), SystemConsts.ARCHIVE_LOG_OPERATION_TYPE, requestObj);
        return archive.getId();
    }

    /**
     * 修改档案
     *
     * @param requestObj 修改档案请求对象
     * @return 提示信息
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean editArchive(EditArchiveReq requestObj) {

        Integer operationUserId = requestObj.getOperationUserId();

        Archive archive = this.getById(requestObj.getId());

        if (archive == null) {
            throw new BusinessException("档案id不存在", "ECCT0708");
        }

        if (archive.getIsDeleted()) {
            throw new BusinessException("档案已经被删除", "ECCT0737");
        }

        // 档案已关联业态，修改时却未上送业态，则不允许修改
        if (archive.getFormatId() != null && requestObj.getFormatId() == null) {
            throw new BusinessException("该档案已关联业态信息，请上送所属业态id！", "ECCT0009");
        }

        // 修改时上送的业态与档案关联业态的不一致，则不允许修改
        if (null != requestObj.getFormatId() && !requestObj.getFormatId().equals(archive.getFormatId())) {
            throw new BusinessException("该档案关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }

        // 校验操作员id是否有效
        QueryUserInfoReq queryUserInfoReq =
            generalService.getQueryUserInfoReq(requestObj, requestObj.getOperationUserId());
        if (!generalService.isUserIdCorrect(queryUserInfoReq)) {
            throw new BusinessException("用户id不存在", "ECCT0102");
        }

        if (!requestObj.getChannel().equals(archive.getChannel())) {
            throw new BusinessException("上送渠道和当前渠道不一致", "ECCT0705");
        }

        if (!requestObj.getOperationUserId().equals(archive.getCreateBy())) {
            throw new BusinessException("修改人和创建人不一致", "ECCT0706");
        }

        if (StringUtils.isNotEmpty(requestObj.getSubmissionDate())) {
            archive.setGmtSubmission(generalService.dateToLocalDateTime(requestObj.getSubmissionDate(), null));
        }

        dozerBeanMapper.map(requestObj, archive);

        if (requestObj.getTemplateId() != null) {
            Map parameter = requestObj.getParameter();
            if (parameter == null) {
                parameter = new HashMap<>();
            }

            File file =
                templateModel.generateContract(requestObj.getTemplateId(), parameter, requestObj.getTableMergeCells());
            // 记录模版使用日志
            Template template = generalService.getTemplate(requestObj.getTemplateId(), requestObj.getChannel());
            templateOperationLogModel.insertOperationLog(template, OperationTypeEnum.INVOKE, requestObj);
            String fileUrl = null;
            try {
                fileUrl = fileService.uploadFile("oss", new FileInputStream(file),
                    "archive" + Calendar.getInstance().getTimeInMillis() + ".docx", commUtils.getOssBucketName());
            } catch (Exception e) {
                throw new BusinessException("上传文件异常", "ECCT0006");
            }
            archive.setUrl(fileUrl);
        }

        generalService.insertArchiveHistory(archive);
        archiveUpdateOperationIdAndDate(archive, operationUserId, true);
        return this.updateById(archive);

    }

    /**
     * 查看档案
     *
     * @param requestObj 查询档案请求
     * @return 档案详情信息传输对象
     */
    public List<ArchiveDto> queryArchive(QueryArchiveReq requestObj) {
        Integer archiveId = requestObj.getArchiveId();
        String channel = requestObj.getChannel();
        String sortField = requestObj.getSortField();
        String sortOrder = requestObj.getSortOrder();
        // 校验操作员id是否有效
        QueryUserInfoReq queryUserInfoReq =
            generalService.getQueryUserInfoReq(requestObj, requestObj.getOperationUserId());
        if (!generalService.isUserIdCorrect(queryUserInfoReq)) {
            throw new BusinessException("用户id不存在", "ECCT0102");
        }

        List<ArchiveDto> archiveDtos = new ArrayList<>();
        QueryWrapper<Archive> queryWrapper = null;
        queryWrapper = new QueryWrapper<>();
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 start
        // queryWrapper.eq("channel", channel);
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 end
        queryWrapper.eq("is_deleted", SystemConsts.IS_DELETED_0);

        PagerInfo pagerInfo = requestObj.getPagerInfo();
        Page<Archive> archivePage = new Page<>(pagerInfo.getPageNum(), pagerInfo.getPageSize());
        if (archiveId != null && archiveId != 0) {
            queryWrapper.eq("id", archiveId);
            archivePage(archivePage, queryWrapper, archiveDtos, pagerInfo);
        } else {// 处理非档案id

            // update by liwq on 2021-08-18 start
            // budId 支持模糊查询
            String busId = requestObj.getBusId();
            if (StringUtils.isNotEmpty(busId)) {
                queryWrapper.like("bus_id", busId);
            }
            // update by liwq on 2021-08-18 end

            // update by liulx on 2022-09-20 start, 若上传业态，则添加业态查询条件
            if (requestObj.getFormatId() != null) {
                queryWrapper.eq("format_id", requestObj.getFormatId());
            }
            // update by liulx on 2022-09-20 end

            // add by liwq on 2021-09-09 start
            // 增加按照个人名称和企业名称模糊查询
            // 注意：为什么不直接在档案表，直接加“个人名称”、“企业名称”字段，好直接模糊查询？
            // 因为“个人名称”、“企业名称“，支持修改，拿修改后的名称查询，就查不到用之前的名字建的档案了；所以采取了下面这种查法，牺牲查询速度换数据准确性；
            List<Integer> naturalPersonIds = new ArrayList<>();
            List<Integer> enterpriseIds = new ArrayList<>();
            // 个人ID
            if (!StringUtils.isEmpty(requestObj.getArchiveNaturalPersonName())) {
                List<UserInfoDto> naturalPersons = userCenterModel
                    .getAllUserInfo(requestObj.getArchiveNaturalPersonName(), channel, requestObj.getOperationUserId());
                if (naturalPersons != null && naturalPersons.size() > 0) {
                    for (UserInfoDto u : naturalPersons) {
                        if ("2".equals(u.getUserBaseInformationDto().getUserType())) {
                            naturalPersonIds.add(u.getUserBaseInformationDto().getUserId());
                        }
                    }
                }

                if (naturalPersonIds == null || naturalPersonIds.size() == 0) {
                    naturalPersonIds.add(-1);
                }

                queryWrapper.in("archive_natural_person_id", naturalPersonIds);
            }
            // 企业ID
            if (!StringUtils.isEmpty(requestObj.getArchiveEnterpriseName())) {
                List<UserInfoDto> enterprises = userCenterModel.getAllUserInfo(requestObj.getArchiveEnterpriseName(),
                    channel, requestObj.getOperationUserId());
                if (enterprises != null && enterprises.size() > 0) {
                    for (UserInfoDto u : enterprises) {
                        if ("0".equals(u.getUserBaseInformationDto().getUserType())) {
                            enterpriseIds.add(u.getUserBaseInformationDto().getUserId());
                        }
                    }
                }

                if (enterpriseIds == null || enterpriseIds.size() == 0) {
                    enterpriseIds.add(-1);
                }

                queryWrapper.in("archive_enterprise_id", enterpriseIds);

            }

            // add by liwq on 2021-09-09 end

            String url = requestObj.getUrl();
            if (StringUtils.isNotEmpty(url)) {
                queryWrapper.like("url", url);
            }

            String name = requestObj.getName();
            if (StringUtils.isNotEmpty(name)) {
                queryWrapper.like("name", name);
            }

            Date submissionStart = requestObj.getSubmissionStart();
            Date submissionEnd = requestObj.getSubmissionEnd();

            if (submissionEnd != null && submissionStart != null && submissionEnd.after(submissionStart)) {
                queryWrapper.ge("gmt_submission", generalService.dateToStr(submissionStart) + " 00:00:00");
                queryWrapper.le("gmt_submission", generalService.dateToStr(submissionEnd) + " 23:59:59");
            } else {
                if (submissionStart != null) {
                    String dateToStr = generalService.dateToStr(submissionStart) + " 00:00:00";
                    queryWrapper.ge("gmt_submission", dateToStr);
                }

                if (submissionEnd != null) {
                    String dateToStr = generalService.dateToStr(submissionEnd) + " 23:59:59";
                    queryWrapper.le("gmt_submission", dateToStr);

                }
            }

            String productType = requestObj.getProductType();
            if (StringUtils.isNotEmpty(productType)) {
                queryWrapper.like("product_type", productType);
            }

            String contractTypeCode = requestObj.getContractTypeCode();
            if (StringUtils.isNotEmpty(contractTypeCode)) {
                queryWrapper.eq("contract_type_code", contractTypeCode);
            }
            // 2021-01-26 支持自定义排序查询 songyf
            if (StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)) {
                if ("createTime".equals(sortField)) {
                    if ("asc".equals(sortOrder)) {
                        queryWrapper.orderByAsc("gmt_create");
                    } else if ("desc".equals(sortOrder)) {
                        queryWrapper.orderByDesc("gmt_create");
                    }
                } else if ("submitTime".equals(sortField)) {
                    if ("asc".equals(sortOrder)) {
                        queryWrapper.orderByAsc("gmt_submission");
                    } else if ("desc".equals(sortOrder)) {
                        queryWrapper.orderByDesc("gmt_submission");
                    }
                } else if ("productType".equals(sortField)) {
                    if ("asc".equals(sortOrder)) {
                        queryWrapper.orderByAsc("product_type");
                    } else if ("desc".equals(sortOrder)) {
                        queryWrapper.orderByDesc("product_type");
                    }
                } else if ("conTypeCode".equals(sortField)) {
                    if ("asc".equals(sortOrder)) {
                        queryWrapper.orderByAsc("contract_type_code");
                    } else if ("desc".equals(sortOrder)) {
                        queryWrapper.orderByDesc("contract_type_code");
                    }
                }
            } else if (StringUtils.isEmpty(sortField) && StringUtils.isEmpty(sortOrder)) {
            } else {
                throw new BusinessException("排序字段和排序方式不可只填一个", "ECCT0000");
            }
            // 分页业务处理并获取档案列表信息
            archivePage(archivePage, queryWrapper, archiveDtos, pagerInfo);
        }
        return archiveDtos;
    }

    /**
     * 删除档案
     *
     * @param requestObj 删除档案请求对象
     * @return 提示信息
     */
    @Transactional(rollbackFor = Exception.class)
    public String deleteArchive(DeleteArchiveReq requestObj) {
        Integer archiveId = requestObj.getArchiveId();
        // 校验操作员id是否有效
        QueryUserInfoReq queryUserInfoReq =
            generalService.getQueryUserInfoReq(requestObj, requestObj.getOperationUserId());
        if (!generalService.isUserIdCorrect(queryUserInfoReq)) {
            throw new BusinessException("用户id不存在", "ECCT0102");
        }

        Archive archive = this.getById(archiveId);

        if (archive == null) {
            throw new BusinessException("档案id不存在", "ECCT0708");
        }

        if (archive.getIsDeleted()) {
            throw new BusinessException("档案已经被删除", "ECCT0737");
        }

        // 档案已关联业态，删除时却未上送业态，则不允许删除
        if (archive.getFormatId() != null && requestObj.getFormatId() == null) {
            throw new BusinessException("该档案已关联业态信息，请上送所属业态id！", "ECCT0009");
        }

        // 删除时上送的业态与档案关联业态的不一致，则不允许删除
        if (requestObj.getFormatId() != null && !requestObj.getFormatId().equals(archive.getFormatId())) {
            throw new BusinessException("该档案关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }

        if (!archive.getChannel().equals(requestObj.getChannel())) {
            throw new BusinessException("上送渠道和当前渠道不一致", "ECCT0705");
        }

        if (!requestObj.getOperationUserId().equals(archive.getCreateBy())) {
            throw new BusinessException("修改人和创建人不一致", "ECCT0706");
        }

        generalService.insertArchiveHistory(archive);
        // 是否删除 1：删除，0：未删除 默认 0
        archive.setIsDeleted(Archive.IS_DELETED_1);
        generalService.archiveUpdateOperationIdAndDate(archive, requestObj.getOperationUserId(), true);
        this.updateById(archive);
        return SUCCESSFUL;
    }

    /**
     * 更新或新建档案基础信息操作
     *
     * @param archive 档案信息
     * @param operationUserId 操作人id
     * @param isUpdate 是否更新
     */
    private void archiveUpdateOperationIdAndDate(Archive archive, Integer operationUserId, Boolean isUpdate) {
        if (isUpdate) {
            // 修改人
            archive.setModifiedBy(operationUserId);
            // 修改时间
            archive.setGmtModified(LocalDateTime.now());
        } else {
            // 创建人
            archive.setCreateBy(operationUserId);
            // 创建时间
            archive.setGmtCreate(LocalDateTime.now());
            // 修改人
            archive.setModifiedBy(operationUserId);
            // 修改时间
            archive.setGmtModified(LocalDateTime.now());
        }

    }

    /**
     * 校验合约是否有效
     *
     * @param contractId 合约id
     * @return 合约对象
     */
    private Contract isContractIdEffective(Integer contractId) {
        Contract contract = contractMapper.selectById(contractId);
        // 合约id必须存在且有效
        if (contract == null) {
            throw new BusinessException("合约id无效", "ECCT0703");
        }
        return contract;
    }

    /**
     * @param archivePage 分页工具
     * @param queryWrapper 分页条件
     * @param archiveDtos 档案详情信息传输对象
     * @param pagerInfo 分页信息
     */
    private void archivePage(Page<Archive> archivePage, QueryWrapper<Archive> queryWrapper,
        List<ArchiveDto> archiveDtos, PagerInfo pagerInfo) {
        List<Archive> records = null;
        IPage<Archive> page = this.page(archivePage, queryWrapper);
        records = page.getRecords();
        if (records != null && records.size() == 0) {
            return;
        }
        records.forEach(archive -> {
            ArchiveDto archiveDto = dozerBeanMapper.map(archive, ArchiveDto.class);
            archiveDtos.add(archiveDto);
        });
        pagerInfo.setTotal(page.getTotal());
    }

    /**
     * 插入操作档案日志
     *
     * @param templateId 模板 id
     * @param operationTypeEnum 操作类型
     * @param req 带所属企业机构 id 基础请求信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void insertArchiveOperationLog(Integer archiveId, String operationType, EnterpriseBaseReqObj req) {
        ArchiveOperationLog log = new ArchiveOperationLog();
        log.setArchiveId(archiveId);
        log.setOperationType(operationType);
        log.setChannel(req.getChannel());
        log.setGmtCreate(LocalDateTime.now());
        log.setCreateBy(req.getOperationUserId());
        log.setGmtModified(LocalDateTime.now());
        log.setModifiedBy(req.getOperationUserId());
        // 查询用户账号信息
        UserInfoDto userInfo = userCenterModel.getUserInfo(req.getOperationUserId(), req.getChannel(),
            req.getOperationUserId(), req.getEnterpriseId());
        String userAccount = userInfo.getUserBaseInformationDto().getUserAccounts();
        log.setOperatorName(userInfo.getUserBaseInformationDto().getUserName());
        log.setOperatorAccount(userAccount);
        // 查询该用户到该类型累计次数
        QueryWrapper<ArchiveOperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("max(totalize) totalize").eq("operator_account", userAccount).eq("operation_type",
            operationType);
        List<Map<String, Object>> mapList = archiveOperationLogMapper.selectMaps(queryWrapper);
        Map<String, Object> resultMap = mapList.get(0);
        if (resultMap != null && resultMap.containsKey("totalize")) {
            int totalize = Integer.parseInt(String.valueOf(resultMap.get("totalize")));
            log.setTotalize(totalize + 1);
        } else {
            log.setTotalize(1);
        }
        archiveOperationLogMapper.insert(log);
    }
}
